// ZFunction.cpp: implementation of the ZFunction class.
//
//////////////////////////////////////////////////////////////////////

#include <string>
#include "ZFunction.h"
#include "Position.h"
#include "P1Diffractor.h"
#include "Pbar1Diffractor.h"
#include "P21Diffractor.h"
#include "P21ccDiffractor.h"
#include "DataHolder.h"


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ZFunction::ZFunction(int i_NInput, char *ZMatrixFile, char *DiffractorFile)
{
  nCall = 0;
  dval = 0.0;
  NInput = i_NInput;

  MyMolecule  = new Molecule(i_NInput, ZMatrixFile);

  int NAtom   = MyMolecule->GetNAtom();	

  newA(XDerivative, NAtom);



  Position *W1, *W2, *W3;

  MyMolecule->GetDiffractorInput(W1,W2,W3);

  char SpaceGroup[15];

  MyMolecule->GetSpaceGroup(SpaceGroup);


  if (!strcmp(SpaceGroup, "P1"))
	  MyDiffractor   = new P1Diffractor(DiffractorFile, W1, W2, W3, MyMolecule->getLabels(), NAtom);
  if (!strcmp(SpaceGroup, "Pbar1"))
	  MyDiffractor   = new Pbar1Diffractor(DiffractorFile, W1, W2, W3, MyMolecule->getLabels(), NAtom);
  if (!strcmp(SpaceGroup, "P2_1"))
	  MyDiffractor   = new P21Diffractor(DiffractorFile, W1, W2, W3, MyMolecule->getLabels(), NAtom);
  if (!strcmp(SpaceGroup, "P 1 21/c 1"))
	  MyDiffractor   = new P21ccDiffractor(DiffractorFile, W1, W2, W3, MyMolecule->getLabels(), NAtom);


  int NIntensity = MyDiffractor->GetNIntensity();

  newA(IDerivative, NIntensity);



  DataHolder *Data;

  MyDiffractor->GetLikelihoodInput(Data);

  MyLikelihood = new Likelihood(Data);

  Result.Size(i_NInput);
}


ZFunction::~ZFunction()
{
deleteA(IDerivative);
deleteA(XDerivative);
delete  MyMolecule;
delete  MyDiffractor;
delete  MyLikelihood;
	
}


//////////////////////////////////////////////////////////////////////
// functions
//////////////////////////////////////////////////////////////////////

double ZFunction::Value(double *Input)
{
Position *AtomPosition = MyMolecule->Build(Input);
double   *Intensity    = MyDiffractor->Build(AtomPosition);

double Answer = MyLikelihood->Build(Intensity);

Result.Input(Answer, Input);

nCall++;

return (Answer); 
}

double ZFunction::Value(vector<double> &Input)
{
  Position *AtomPosition = MyMolecule->Build(Input);
  double   *Intensity    = MyDiffractor->Build(AtomPosition);

  double Answer = MyLikelihood->Build(Intensity);

  Result.Input(Answer, Input);

  nCall++;

  return (Answer); 
}

void ZFunction::BuildDerivative(double *Input, double *Derivative)
{
	dval = ZFunction::Value(Input);

	MyLikelihood->BuildDerivatives(IDerivative);

	MyDiffractor->TransformDerivatives(IDerivative,XDerivative);

	MyMolecule->TransformDerivatives(XDerivative,Derivative);	

  //return (1.0);
}

// distance from know global minimum which is located at the origin
double ZFunction::distanceFromGlobalMinimum(double *solution)
{
  return MyMolecule->distanceFromInputZmatrix(solution);
}
